package main

import (
	"flag"
	"fmt"
	"log"
	"os"
	"runtime"
	"strings"
	"time"

	"github.com/tarm/serial"
)

type Cmd struct {
	Name    string
	Baud    int
	Data    int
	Stop    int
	Timeout int
	Parity  string
	Self    bool
}

func cmd(com *Cmd) {
	flag.StringVar(&com.Name, "n", "", "com name, default linux /dev/ttyS0, windows COM1")
	flag.IntVar(&com.Baud, "b", 9600, "baud rate, default 9600")
	flag.IntVar(&com.Timeout, "t", 0, "timeout for read(unit ms), default 0 is indefinite wait")
	flag.BoolVar(&com.Self, "S", false, "true self send and receive,false for send to other, default false")
	flag.IntVar(&com.Data, "d", 8, "data bit, default 8")
	flag.IntVar(&com.Stop, "s", 1, "stop bit, default 1,must be 1,2,or 15")
	flag.StringVar(&com.Parity, "p", "N", `parity check, 
	ParityNone  Parity = 'N'
	ParityOdd   Parity = 'O'
	ParityEven  Parity = 'E'
	ParityMark  Parity = 'M' // parity bit is always 1
	ParitySpace Parity = 'S'`)

	flag.Parse()

	sysType := runtime.GOOS

	// fmt.Println(sysType)

	if com.Name == "" {
		if sysType == "linux" {
			com.Name = "/dev/ttyS0"
			// LINUX系统
		} else if sysType == "windows" {
			com.Name = "COM1"
			// windows系统
		}
	}
	com.Parity = strings.ToUpper(com.Parity)
	if com.Parity != "N" && com.Parity != "O" && com.Parity != "E" && com.Parity != "S" && com.Parity != "M" {
		log.Fatal("parity set error,parity must be N,O,E,M orS,current set ", com.Parity)
	}
	if com.Data < 5 || com.Data > 8 {
		log.Fatal("set data bit error,must between [5,8],current set ", com.Data)
	}
	if com.Stop != 1 && com.Stop != 2 && com.Stop != 15 {
		log.Fatal("set stop bit error,must be 1,2 or 15 ,current set ", com.Stop)
	}
}

func main() {
	var com Cmd
	cmd(&com)

	// fmt.Println(com)
	// c := &serial.Config{Name: "/dev/ttyS0", Baud: 115200, Size: 7}
	c := new(serial.Config)

	c.Name = com.Name
	c.Baud = com.Baud

	c.Parity = serial.Parity(com.Parity[0])

	c.Size = byte(com.Data)

	c.StopBits = serial.StopBits(com.Stop)
	c.ReadTimeout = time.Millisecond * time.Duration(com.Timeout)

	// fmt.Println(c)

	c.Parity = serial.ParityNone

	// fmt.Println(c)

	s, err := serial.OpenPort(c)
	if err != nil {
		log.Fatal("open serial error:", err)
	}

	if com.Self {
		selfloop(s)
	} else {
		doloop(s)
	}

}

func doloop(s *serial.Port) {
	var buffer [512]byte

	// var tmp int
	// Ch := make(chan int)

	go func() {
		for {

			// <-Ch
			// time.Sleep(time.Duration(time.Millisecond * 1000))
			buf := make([]byte, 128)
			n, err := s.Read(buf)
			if err != nil {
				log.Fatal(err)
			}
			// log.Printf("received: %q", string(buf[:n]))
			log.Printf("received: %s", string(buf[:n]))
		}
	}()

	for {
		fmt.Printf("Enter msg for send [exit for quit program]:  ")
		n, err := os.Stdin.Read(buffer[:])
		if err != nil {

			fmt.Println("read error:", err)
			return

		}
		// cp := strings.Compare(string(buffer[:n-1]), "exit")
		// if cp == 0 {
		// 	break
		// }

		sysType := runtime.GOOS

		if sysType == "linux" {
			n = n - 1
			// if string(buffer[:n-1]) == "exit" {
			// 	break
			// }
		} else if sysType == "windows" {

			n = n - 2
		}

		if string(buffer[:n]) == "exit" {
			break
		}
		fmt.Println("Msg for send size:", n, ", content:", string(buffer[:n]))

		m := 0
		// var dst []byte
		// for sz := 0; sz < n; sz = sz + m {
		// base64.StdEncoding.Encode(dst, buffer[0:n])
		// sEnc := base64.StdEncoding.EncodeToString([]byte(buffer[0:n]))
		m, err = s.Write([]byte(buffer[:n]))
		// m, err = s.Write([]byte(dst))
		if err != nil {
			log.Fatal(err)
		}
		log.Println("send size ", m, " total size", n)

		time.Sleep(time.Duration(time.Millisecond * 100))
		// Ch <- tmp
		// time.Sleep(time.Duration(time.Millisecond * 100))
		// sz?= sz+m
		// }

	}

}

func selfloop(s *serial.Port) {

	var buffer [512]byte

	for {
		fmt.Printf("Enter msg for send [exit for quit program]:  ")
		n, err := os.Stdin.Read(buffer[:])
		if err != nil {

			fmt.Println("read error:", err)
			return

		}

		sysType := runtime.GOOS

		if sysType == "linux" {
			n = n - 1

		} else if sysType == "windows" {

			n = n - 2
		}

		if string(buffer[:n]) == "exit" {
			break
		}
		fmt.Println("Msg for send size:", n, ", content:", string(buffer[:n]))

		m := 0
		m, err = s.Write([]byte(buffer[:n]))

		if err != nil {
			log.Fatal(err)
		}
		log.Println("send size ", m, " total size", n)

		// time.Sleep(time.Duration(time.Millisecond * 100))
		// Ch <- tmp
		time.Sleep(time.Duration(time.Millisecond * 100))

		buf := make([]byte, 128)
		n, err = s.Read(buf)
		if err != nil {
			log.Fatal(err)
		}

		log.Printf("received size: %d, content: %s", n, string(buf[:n]))

	}

}
